package com.xjzd.jvm;

/**
 * 指令重排序导致结果不一致的多个示例
 * 演示了CPU和编译器优化可能导致的指令重排序问题
 */
public class InstructionReorderDemo {

    /**
     * 示例1: 双重检查锁定的单例模式问题
     * 由于指令重排序，可能返回一个未完全初始化的对象
     */
    static class Singleton {
        // 不使用volatile可能导致指令重排序问题
        private static Singleton instance;
        private int value = 100;

        private Singleton() {
            // 模拟复杂的初始化过程
            this.value = 200;
        }

        public static Singleton getInstance() {
            if (instance == null) {  // 第一次检查
                synchronized (Singleton.class) {
                    if (instance == null) {  // 第二次检查
                        // 这里可能发生指令重排序：
                        // 正常顺序：1.分配内存 2.初始化对象 3.将引用指向内存
                        // 重排后：1.分配内存 2.将引用指向内存 3.初始化对象
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }

        public int getValue() {
            return value;
        }
    }

    /**
     * 示例2: 经典的指令重排序问题
     * 两个线程交叉执行时，由于重排序导致意外结果
     */
    static class ReorderExample {
        private static int x = 0, y = 0;
        private static int a = 0, b = 0;

        public static void testReorder() throws InterruptedException {
            int count = 0;
            int iterations = 1000000;

            System.out.println("=== 示例2: 经典指令重排序问题 ===");
            System.out.println("开始测试 " + iterations + " 次...\n");

            for (int i = 0; i < iterations; i++) {
                x = y = a = b = 0;

                Thread thread1 = new Thread(() -> {
                    a = 1;  // 操作1
                    x = b;  // 操作2
                });

                Thread thread2 = new Thread(() -> {
                    b = 1;  // 操作3
                    y = a;  // 操作4
                });

                thread1.start();
                thread2.start();
                thread1.join();
                thread2.join();

                // 如果没有指令重排序，x和y不可能同时为0
                // 可能的执行顺序（无重排）：
                // 1->2->3->4: x=0, y=1
                // 1->3->2->4: x=1, y=1
                // 1->3->4->2: x=1, y=1
                // 3->1->2->4: x=1, y=1
                // 3->1->4->2: x=1, y=1
                // 3->4->1->2: x=1, y=0
                // 但如果发生重排序，可能出现 x=0, y=0 的情况
                if (x == 0 && y == 0) {
                    count++;
                    if (count <= 5) {  // 只打印前5次
                        System.out.println("第 " + count + " 次检测到重排序: x=" + x + ", y=" + y);
                    }
                }
            }

            System.out.println("\n总共检测到重排序次数: " + count + " / " + iterations);
            System.out.println("重排序发生概率: " + String.format("%.4f%%", (count * 100.0 / iterations)));
        }
    }

    /**
     * 示例3: 发布未初始化的对象
     * 由于指令重排序，其他线程可能看到未完全初始化的对象
     */
    static class UnsafePublication {
        private static Resource resource;
        private static boolean initialized = false;

        static class Resource {
            private int value1;
            private int value2;
            private String name;

            public Resource() {
                this.value1 = 100;
                this.value2 = 200;
                this.name = "Resource";
            }

            @Override
            public String toString() {
                return "Resource{value1=" + value1 + ", value2=" + value2 + ", name='" + name + "'}";
            }
        }

        public static void testUnsafePublication() throws InterruptedException {
            System.out.println("\n=== 示例3: 发布未初始化的对象 ===");
            
            int count = 0;
            for (int i = 0; i < 10000000; i++) {
                resource = null;

                // 发布线程
                Thread publisher = new Thread(() -> {
                    resource = new Resource();  // 可能发生指令重排序
                });

                // 读取线程
                Thread reader = new Thread(() -> {
                    if (resource != null) {
                        // 由于指令重排序，可能看到未完全初始化的resource
                        if (resource.value1 == 0 || resource.value2 == 0 || resource.name == null) {
                            System.out.println("检测到未完全初始化的对象: " + resource);
                        }
                    }
                });

                publisher.start();
                reader.start();
                publisher.join();
                reader.join();
            }
        }
    }

    /**
     * 示例4: 使用volatile解决指令重排序问题
     */
    static class VolatileSolution {
        private volatile static int x = 0, y = 0;
        private volatile static int a = 0, b = 0;

        public static void testWithVolatile() throws InterruptedException {
            int count = 0;
            int iterations = 1000000;

            System.out.println("\n=== 示例4: 使用volatile防止重排序 ===");
            System.out.println("开始测试 " + iterations + " 次...\n");

            for (int i = 0; i < iterations; i++) {
                x = y = a = b = 0;

                Thread thread1 = new Thread(() -> {
                    a = 1;  // volatile写
                    x = b;  // volatile读
                });

                Thread thread2 = new Thread(() -> {
                    b = 1;  // volatile写
                    y = a;  // volatile读
                });

                thread1.start();
                thread2.start();
                thread1.join();
                thread2.join();

                if (x == 0 && y == 0) {
                    count++;
                }
            }

            System.out.println("使用volatile后，检测到重排序次数: " + count + " / " + iterations);
            if (count == 0) {
                System.out.println("✓ volatile成功防止了指令重排序！");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("========================================");
        System.out.println("指令重排序导致结果不一致的示例演示");
        System.out.println("========================================\n");

        // 运行示例2：经典指令重排序问题
        // ReorderExample.testReorder();

        // 运行示例3：发布未初始化的对象
        UnsafePublication.testUnsafePublication();

        // 运行示例4：使用volatile解决问题
        // VolatileSolution.testWithVolatile();

        System.out.println("\n========================================");
        System.out.println("演示完成！");
        System.out.println("========================================");
    }
}
